﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace DecisionTree
{
    class TreeD : Methods
    {
        public delegate bool delegatVerificationNode(NodesLR nodeLR, double chMVN, int chMNV, int chMNVP, RichTextBox RT);
        public delegate NodesLR delegat1(double[][] AJ, RichTextBox RT, int mNNCH);

        //public static double[][] AJ;
        public static DateTime dateOnly = DateTime.Now;
        public static String date = Convert.ToString(dateOnly.ToString("yyyyMMdd-HHmm"));//nazwa dla katalogu

        public static int GNN = 0, L = 1, N = 1, P = 0;
        //GNN-Global Node Number | L-Level | N-Node | P-Parent |
        //mL - Max Level    

        //wczytywanie pliku
        static char[] charSeparators = new char[] { ' ', '\t' };

        //regula stopu
        static public double mVN; //minimalna wariancja wezla
        static public int mNV; //minimalna ilosc wektorow potomka L lub R
        static public int mL; //max poziom
        static public int mNVP;//minimalna  licznosc potomka rodzica
        static public Queue<int> PNS = new Queue<int>();

        public static void Tree(String name, RichTextBox rTree, RichTextBox rVerification, delegat1 metodaD, delegatVerificationNode verificationNodeT)
        {
            rTree.Clear();
            // dane poczatkowe
            int nL = 2, nR = 3, nF = 1;// numery plików poczatkowych 

            String nfile = "00";// numeru 
            String fileName = "Dane" + name + date + "\\Set" + nfile + nF + ".txt";
            String fileNameL = "Dane" + name + date + "\\Set" + nfile + nL + ".txt";
            String fileNameR = "Dane" + name + date + "\\Set" + nfile + nR + ".txt";
            String fileNameT = "Dane" + name + date + "\\Tree.txt";

            StreamWriter wfR;
            StreamWriter wfL;
            int nN = 0, nN2 = 1, nP = 1; // zmienne potrzebne do zmiany poziomu rodzica wezla
            int numFile = 1;// do sprawdzania czy sa pliki jeszcze do wczytania

            //tworzenie katalogu            
            Directory.CreateDirectory(@"Dane" + name + date);//tworzenie katalogu DANE+DATA+CZAS

            FileStream fsT = new FileStream(fileNameT, FileMode.Append, FileAccess.Write);//Tworzenie plików tree do zapisywania wezlow sredniej wariancji itd...
            StreamWriter wfT = new StreamWriter(fsT);
            rTree.Clear();
            wfT.WriteLine("GNNumber Level    Node    Parent  ChildL  ChildR  Mean        Variance    NumVect SANumber    SAValue");
            rTree.AppendText(Convert.ToString("GNNumber   Poziom    Wezel   Rodzic   ChildL   ChildR   Mean      Variance      NumVect   SAN   SpliAValue \n"));

            {//tworzenie pierwszego pliku do wczytania

                saveFile(fileName);//zapisujemy pierwszy plik do wczytania
            }

            int nRL = AJ[0].Length;//max ilosc powtorzen petli

            for (int w = 1; w < nRL; w++)//Wczyttywanie wezla z nr----------------------------------------------------------
            {
                if (w > numFile) { break; }//przerywanie petli gdy juz nie ma wiecej plikow do wczytania

                if (nP == 2) { P++; nP = 0; }//zmiana rodzica

                GNN++; //wezel globalny

                fileName = "Dane" + name + date + "\\Set" + nfile + w + ".txt";//wczytywanie wezla
                {
                    readFile(fileName);//wczytywanie pliku do obliczen
                }

                while (PNS.Count > 0)//sprawdzanie czy wezel sie dzielil na CHL i CHR 
                {
                    if (P == (int)PNS.Peek())
                    {
                        PNS.Dequeue();
                        P++;
                    }
                    else
                    {
                        break;
                    }
                }

                NodesLR node = metodaD(AJ, rVerification, mNV);//metoda szuka najlepszego punktu podzialu i zwraca wezel dla Tree
                node.L = L;
                node.GNN = GNN;
                node.N = N;
                node.P = P;
                node.CHL = nL;
                node.CHR = nR;

                if (verificationNodeT(node, mVN, mNV, mNVP, rVerification)) //if sprawdzajcy czy var q CHL i CHR jest wieksza od minimalnej i sprawdza tez ilosc wektorow
                {

                    nN += 2;
                    numFile += 2; //zliczanie plikow

                    //po sprawdzeniu tworzymy plik z wezlami
                    fileNameL = "Dane" + name + date + "\\Set" + nfile + nL + ".txt";
                    fileNameR = "Dane" + name + date + "\\Set" + nfile + nR + ".txt";
                    FileStream fsL = new FileStream(fileNameL, FileMode.Append, FileAccess.Write);//Tworzenie plików do zapisywania zbiorow L
                    FileStream fsR = new FileStream(fileNameR, FileMode.Append, FileAccess.Write);//Tworzenie plików do zapisywania zbiorow P

                    wfR = new StreamWriter(fsR);
                    wfL = new StreamWriter(fsL);

                    for (int i = 0; i < AJ[0].Length; i++)//zapisywanie wektorow do plikow L i R 
                    {
                        // rVerification.AppendText("Tree" + "  SV =" + AJ[node.SAN - 1][i]+"SAV  "+node.SAV+ "\n");

                        if (node.isV1A)
                        {
                            if (node.ML < node.MR)// jesli varL jest wieksze, to zamiana zbiorow z L na R
                            {

                                if (AJ[node.SAN - 1][i] < node.SAV) //atrybut dzielacy pi-kolumna przy ktorej dzielimy i-wiersze do podziału na CHL i CHR
                                {
                                    for (int j = 0; j < AJ.Length; j++)
                                    {
                                        wfL.Write(Convert.ToString(AJ[j][i]) + " ");
                                    }
                                    wfL.WriteLine();
                                }
                                else
                                {
                                    for (int j = 0; j < AJ.Length; j++)
                                    {
                                        wfR.Write(Convert.ToString(AJ[j][i]) + " ");
                                    }
                                    wfR.WriteLine();
                                }
                            }
                            else
                            {
                                if (AJ[node.SAN - 1][i] < node.SAV) //atrybut dzielacy pi-kolumna przy ktorej dzielimy i-wiersze do podziału na CHL i CHR
                                {
                                    for (int j = 0; j < AJ.Length; j++)
                                    {
                                        wfR.Write(Convert.ToString(AJ[j][i]) + " ");
                                    }
                                    wfR.WriteLine();
                                }
                                else
                                {
                                    for (int j = 0; j < AJ.Length; j++)
                                    {
                                        wfL.Write(Convert.ToString(AJ[j][i]) + " ");
                                    }
                                    wfL.WriteLine();
                                }
                            }
                        }
                        else//---------------------------------------------V2A------------------------------------
                        {

                            double vAS = 0; // wartosc dwoch atrybutow podzoalu

                            if (node.mA < 7)// sprawdzanie ktory atrybut ma byc mnozony
                            {
                                vAS = AJ[node.nC1][i] + AJ[node.nC2][i] * node.lS;
                            }
                            else
                            {
                                vAS = AJ[node.nC1][i] * node.lS + AJ[node.nC2][i];
                            }

                            if (node.ML < node.MR)// jesli varL jest wieksze, to zamiana zbiorow z L na R
                            {

                                if (vAS < node.SAV) //atrybut dzielacy pi-kolumna przy ktorej dzielimy i-wiersze do podziału na CHL i CHR
                                {
                                    for (int j = 0; j < AJ.Length; j++)
                                    {
                                        wfL.Write(Convert.ToString(AJ[j][i]) + " ");
                                    }
                                    wfL.WriteLine();
                                }
                                else
                                {
                                    for (int j = 0; j < AJ.Length; j++)
                                    {
                                        wfR.Write(Convert.ToString(AJ[j][i]) + " ");
                                    }
                                    wfR.WriteLine();
                                }
                            }
                            else
                            {

                                if (vAS < node.SAV) //atrybut dzielacy pi-kolumna przy ktorej dzielimy i-wiersze do podziału na CHL i CHR
                                {
                                    for (int j = 0; j < AJ.Length; j++)
                                    {
                                        wfR.Write(Convert.ToString(AJ[j][i]) + " ");
                                    }
                                    wfR.WriteLine();
                                }
                                else
                                {
                                    for (int j = 0; j < AJ.Length; j++)
                                    {
                                        wfL.Write(Convert.ToString(AJ[j][i]) + " ");
                                    }
                                    wfL.WriteLine();
                                }
                            }

                        }


                    }

                    rTree.AppendText(Convert.ToString(node.GNN + "                   " + node.L + "             " + node.N + "              " + node.P + "           " + node.CHL + "           " + node.CHR + "       " + Math.Round(node.M, 5) + "        " + Math.Round(node.V, 5) + "       " + node.NV + "       " + node.SAN + "         " + Math.Round(node.SAV, 5) + "\n"));

                    if (node.M < 0)//sprawdzenie do zapisu pliku czy liczba ujemna, zeby przestawic o jedno miejsce
                    {
                        wfT.WriteLine(node.GNN + "          " + node.L + "        " + node.N + "       " + node.P + "       " + node.CHL + "       " + node.CHR + "       " + Math.Round(node.M, 5) + "     " + Math.Round(node.V, 5) + "    " + node.NV + "     " + node.SAN + "           " + Math.Round(node.SAV, 5));//ZApisywanie do pliku tree
                    }
                    else
                    {
                        wfT.WriteLine(node.GNN + "          " + node.L + "        " + node.N + "       " + node.P + "       " + node.CHL + "       " + node.CHR + "       " + Math.Round(node.M, 5) + "      " + Math.Round(node.V, 5) + "    " + node.NV + "     " + node.SAN + "           " + Math.Round(node.SAV, 5));//ZApisywanie do pliku tree
                    }

                    nL += 2;// zwiekszamy nazwe pliku o 2
                    nR += 2;// zwiekszamy nazwe pliku o 2

                    wfL.Close();
                    wfR.Close();

                }//koniec if sprawdzajacy CHL i CHR czy sie dzieli
                else
                {

                    PNS.Enqueue(node.GNN);//jesli sie rodzic nie dzieli to musimy zapamietac
                    if (node.M == 0)
                    {
                        node.M = average(AJ[AJ.Length - 1]); node.V = variance(AJ[AJ.Length - 1], average(AJ[AJ.Length - 1]));
                        node.NV = AJ[0].Length;
                    }
                    if (node.NV < mNV || node.V < mVN) { node.SAN = 0; node.SAV = 0; }

                    //rVerification.AppendText(Convert.ToString(node.GNN + "                   " + node.L + "             " + node.N + "              " + node.P + "           " + node.CHL + "           " + node.CHR + "       " + Math.Round(node.M, 5) + "        " + Math.Round(node.V, 5) + "       " + node.NV + "       " + node.SAN + "         " + Math.Round(node.SAV, 5) + "\n"));
                    rTree.AppendText(Convert.ToString(node.GNN + "                   " + node.L + "             " + node.N + "              " + node.P + "           " + 0 + "           " + 0 + "       " + Math.Round(node.M, 5) + "        " + Math.Round(node.V, 5) + "       " + node.NV + "       " + node.SAN + "         " + Math.Round(node.SAV, 5) + "\n"));
                    if (node.M < 0)// warunek do formatowania tekstu w pliku
                    {
                        wfT.WriteLine(node.GNN + "          " + node.L + "        " + node.N + "       " + node.P + "       " + 0 + "       " + 0 + "       " + Math.Round(node.M, 5) + "     " + Math.Round(node.V, 5) + "    " + node.NV + "     " + node.SAN + "           " + Math.Round(node.SAV, 5));//ZApisywanie do pliku tree
                    }
                    else
                    {
                        wfT.WriteLine(node.GNN + "          " + node.L + "        " + node.N + "       " + node.P + "       " + 0 + "       " + 0 + "       " + Math.Round(node.M, 5) + "      " + Math.Round(node.V, 5) + "    " + node.NV + "     " + node.SAN + "           " + Math.Round(node.SAV, 5));//ZApisywanie do pliku tree
                    }
                }

                if (N == nN2) { L++; nN2 = nN; nN = 0; N = 0; }//zwiekszanie poziomu gdy przejdziemy przez wszystkie wezly na danym poziomie
                N++;
                nP++;// do zmiany rodzica 

                if (L > mL) { break; } //po osiegnieciu poziomu konczymy 

            } //petla dla wezla w            
            wfT.Close(); // zamykanie plik    

        }//TreeD  
    }
}
